package lang;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import bean.BeanParseException;
import exception.JAFRuntimeException;

/**
 * 时间的抽象类，不做单独使用.
 * 
 * @author 王永弟
 * @since JDK1.4
 * @copyright 广州从兴电子开发有限公司-电子渠道业务部
 * @date 2011-5-1
 */
public abstract class AbstractDate implements java.io.Serializable, Cloneable, Comparable<AbstractDate> {
	private static final long serialVersionUID = 1L;
	/**
	 * 当前日期的格式化格式
	 */
	protected String formatter = "yyyy-MM-dd HH:mm:ss";
	/**
	 * 日期保存的Calendar实例
	 */
	protected Calendar cal = Calendar.getInstance();

	protected AbstractDate() {
	}

	/**
	 * <方法描述> 根据毫秒对象，设置时间
	 * 
	 * @param milliseconds
	 */
	public abstract void setTime(long milliseconds);

	/**
	 * 设置日期初始化格式
	 * 
	 * @param formatter
	 */
	public void setFormatter(String formatter) {
		this.formatter = formatter;
	}

	public int compareTo(AbstractDate anotherDate) {
		long thisTime = cal.getTimeInMillis();
		long anotherTime = anotherDate.getMilliTime();
		return (thisTime < anotherTime ? -1 : (thisTime == anotherTime ? 0 : 1));
	}

	/**
	 * 获取时间的毫秒数
	 * 
	 * @return 日期毫秒数
	 */
	public long getMilliTime() {
		return cal.getTimeInMillis();
	}

	@Override
	public String toString() {
		SimpleDateFormat format = new SimpleDateFormat(formatter);
		return format.format(cal.getTime());
	}

	@Override
	public Object clone() {
		AbstractDate d = null;
		try {
			d = (AbstractDate) super.clone();
			d.cal = (Calendar) cal.clone();
		} catch (CloneNotSupportedException e) {
		} // Won't happen
		return d;
	}

	@Override
	public boolean equals(Object obj) {
		return obj instanceof Date && cal.getTimeInMillis() == ((AbstractDate) obj).getMilliTime();
	}

	@Override
	public int hashCode() {
		long thisTime = cal.getTimeInMillis();
		return (int) thisTime ^ (int) (thisTime >> 32);
	}

	/**
	 * 比较两个日期的值，如果当前日期小于参数日期，返回true，否则返回false
	 * 
	 * @param when
	 * @return true or false
	 */
	public boolean before(AbstractDate when) {
		return cal.getTimeInMillis() < when.getMilliTime();
	}

	/**
	 * 比较两个日期的值，如果当前日期大于参数日期，返回true，否则返回false
	 * 
	 * @param when
	 * @return true or false
	 */
	public boolean after(AbstractDate when) {
		return cal.getTimeInMillis() > when.getMilliTime();
	}

	/**
	 * 将当前日期转为指定格式的字符串
	 * 
	 * @param formatter
	 *            日期格式
	 * @return 日期的字符串
	 */
	public String toString(String formatter) {
		SimpleDateFormat format = new SimpleDateFormat(formatter);
		return format.format(cal.getTime());
	}

	/**
	 * <方法描述> 将指定的字符串，根据指定格式，转化为日期
	 * 
	 * @param str
	 *            日期字符串
	 * @param formatter
	 *            日期对应的格式
	 * @return 日期对象
	 * @throws JAFRuntimeException
	 *             无法转换时抛出
	 */
	public static <T extends AbstractDate> T parse(String str, String formatter, Class<T> clazz) {
		T date = null;
		SimpleDateFormat format = new SimpleDateFormat(formatter);
		java.util.Date ud = null;
		try {
			date = clazz.newInstance();
			ud = paserDate(str, format);
		} catch (BeanParseException e) {
			ud = paserDate(repairStrByFormatter(str, formatter), format);
		} catch (Exception e) {
			throw new BeanParseException("cannot create instance of class:" + clazz, e);
		}
		date.setTime(ud.getTime());
		return date;
	}

	/**
	 * <方法描述> 将字符串，转化化java.util.date
	 * 
	 * @param str
	 * @param format
	 * @return
	 */
	private static java.util.Date paserDate(String str, SimpleDateFormat format) {
		java.util.Date ud = null;
		try {
			ud = format.parse(str);
		} catch (Exception e) {
			throw new BeanParseException("the string " + str + " cannot parse to date of format " + format.toPattern(),
					e);
		}
		return ud;
	}

	/**
	 * <方法描述> 获取配置的字符串值列表
	 * 
	 * @param str
	 * @param p
	 * @return
	 */
	private static List<String> getMatchArray(String str, Pattern p) {
		Matcher m = p.matcher(str);
		List<String> s = new ArrayList<String>();
		while (m.find()) {
			s.add(m.group());
		}
		return s;
	}

	/**
	 * <方法描述> 根据格式，修复数据值
	 * 
	 * @param str
	 * @param formatter
	 * @return
	 */
	private static String repairStrByFormatter(String str, String formatter) {
		Pattern pSplit = Pattern.compile("[^A-Za-z0-9]+");
		Pattern pElement = Pattern.compile("[A-Za-z0-9]+");
		Pattern pValue = Pattern.compile("[0-9]+");
		List<String> splits = getMatchArray(formatter, pSplit);
		List<String> elements = getMatchArray(formatter, pElement);
		List<String> values = getMatchArray(str, pValue);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < elements.size(); i++) {
			if (i < values.size()) {
				String value = values.get(i);
				if (value.length() > elements.get(i).length()) {
					throw new BeanParseException("the string " + str + " cannot parse to date of format " + formatter);
				}
				sb.append(values.get(i));
				sb.append(splits.get(i));
			} else {
				sb.append("0");
				if (i < splits.size())
					sb.append(splits.get(i));
			}
		}
		return sb.toString();
	}

	/**
	 * 获得封装的Calendar实例
	 */
	public Calendar toCalendar() {
		return this.cal;
	}
}
